﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Collections;
using Microsoft.CSharp;
using System.CodeDom.Compiler;
using System.Reflection;
using System.IO;

namespace Commons
{
    public class CodeGen
    {
        public object GetObject(string objName)
        {
            string typeName = objName.IndexOf(".") > 0 ? objName : "Business.Entities." + FirstUpper(objName);
            if (File.Exists(AppDomain.CurrentDomain.BaseDirectory + @"bin\Business.dll"))
            {
                Assembly loadMod = Assembly.LoadFile(AppDomain.CurrentDomain.BaseDirectory + @"bin\Business.dll");
                if (loadMod != null)
                {
                    Type t = loadMod.GetType(typeName);
                    if (t != null)
                    {
                        return Activator.CreateInstance(t);
                    }
                }
            }
            Assembly asb = CompileCode(objName);
            if (asb != null) 
            {
                return asb.CreateInstance(typeName);
            }
            return null;
        }

        public Assembly CompileCode(string dbTableName)
        {
            if (!IsTableExist(dbTableName)) return null;
            CSharpCodeProvider provider = new CSharpCodeProvider();
            CompilerParameters parameter = new CompilerParameters();
            parameter.ReferencedAssemblies.Add("System.dll");
            parameter.ReferencedAssemblies.Add("System.Data.dll");
            parameter.ReferencedAssemblies.Add(AppDomain.CurrentDomain.BaseDirectory + @"bin\Commons.dll");
            parameter.GenerateExecutable = false;
            parameter.GenerateInMemory = true;
            parameter.OutputAssembly = "Business";
            CompilerResults result = provider.CompileAssemblyFromSource(parameter,
            GetCodeByTableName(dbTableName));
            if (result.Errors.Count > 0)
            {
                return null;
            }
            else
            {
                return result.CompiledAssembly;
            }
        }

        private Boolean IsTableExist(string dbTableName)
        {
            DbHelper helper = DbHelper.getHelper();
            int i = helper.setToEntity<int>(helper.ExcuteQuery("select count(*) from sysobjects where type='u' and name=@tname", dbTableName));
            if (i != 1)
            {
                return false;
            }
            return true;
        }

        public string GetCodeByTableName(string table)
        {
            try
            {
                DbHelper helper = DbHelper.getHelper();
                StringBuilder sb = new StringBuilder();
                Hashtable param = new Hashtable();
                string tlbName = table;
                param.Add("@table_name", table);
                DataTable keyinfo = helper.ExcuteProcudure("sys.sp_pkeys", param).Tables[0];
                string dbversion = helper.ExcuteDataTableQuery("select @@version", "").Rows[0][0].ToString();
                StringBuilder sql = new StringBuilder();
                sql.Append(@"
                   SELECT 
	                col.name AS CNAME,
	                COLTYPE = CASE col.xtype 
		                WHEN 35 THEN 'string'
		                WHEN 36 THEN 'decimal'
		                WHEN 48 THEN 'int'
		                WHEN 52 THEN 'int'
		                WHEN 56 THEN 'int'
		                WHEN 58 THEN 'string'
		                WHEN 59 THEN 'decimal'
		                WHEN 60 THEN 'string'
		                WHEN 61 THEN 'string'
		                WHEN 62 THEN 'float'
		                WHEN 98 THEN 'string'
		                WHEN 99 THEN 'string'
		                WHEN 104 THEN 'int'
		                WHEN 106 THEN 'decimal'
		                WHEN 108 THEN 'decimal'
		                WHEN 122 THEN 'string'
		                WHEN 127 THEN 'long'
		                WHEN 165 THEN 'string'
		                WHEN 167 THEN 'string'
		                WHEN 173 THEN 'decimal'
		                WHEN 175 THEN 'string'
		                WHEN 189 THEN 'string'
		                WHEN 230 THEN 'string'
		                WHEN 231 THEN 'string'
		                WHEN 239 THEN 'string'
	                END,
                    ISID = CASE col.xtype WHEN 36 THEN 'true' ELSE 'false' END,
	                col.COLORDER AS COLNO,
                    pro.value AS COMMENT,
	                obj.name as TNAME
                FROM syscolumns col
                LEFT JOIN sysobjects obj
                on obj.id = col.id");
                if (dbversion.Contains("SQL Server 2005"))
                {
                    sql.Append(@"
                LEFT JOIN sys.extended_properties pro
                on obj.id = pro.major_id and col.colid = pro.minor_id");
                }
                else if (dbversion.Contains("SQL Server 2000"))
                {
                    sql.Append(@"
                LEFT JOIN sysproperties pro
                on obj.id = pro.major_id and col.colid = pro.smallid");
                }
                sql.Append(@"
                WHERE obj.id = (select id from sysobjects where type='u' and name=@tname) ");
                DataTable dt = helper.ExcuteDataTableQuery(sql.ToString(), table);
                sb.AppendLine("using System;");
                sb.AppendLine("using System.Data;");
                sb.AppendLine("using System.Text;");
                sb.AppendLine("using System.Collections;");
                sb.AppendLine("using System.Collections.Generic;");
                sb.AppendLine("using Commons;");
                sb.AppendLine("");
                sb.AppendLine("namespace Business.Entities");
                sb.AppendLine("{");
                sb.AppendLine("    [DbTable(Name = \"" + table + "\")]");

                sb.AppendLine("    public class " + FirstUpper(table));
                sb.AppendLine("    {");
                foreach (DataRow dr in dt.Rows)
                {
                    if (dr["COMMENT"] != DBNull.Value)
                    {
                        sb.AppendLine("        // " + dr["COMMENT"].ToString());
                    }
                    sb.AppendLine("        private " + dr["COLTYPE"] + " " + dr["CNAME"].ToString().ToLower() + ";");
                    sb.AppendLine("");
                    sb.AppendLine("        [DbColumn(ColumnID = \"" + dr["CNAME"].ToString() + "\", IsKey = " + IsKey(dr["CNAME"].ToString(), keyinfo).ToString().ToLower() + ", IsIdentity = " + dr["ISID"].ToString() + " )]");
                    sb.AppendLine("        public " + dr["COLTYPE"] + " " + FirstUpper(dr["CNAME"].ToString()));
                    sb.AppendLine("        {");
                    sb.AppendLine("            get { return " + dr["CNAME"].ToString().ToLower() + "; }");
                    sb.AppendLine("            set { this." + dr["CNAME"].ToString().ToLower() + " = value; }");
                    sb.AppendLine("        }");
                    sb.AppendLine("");
                }
                sb.AppendLine("    }");
                sb.AppendLine("}");
                return sb.ToString();

            }
            catch (Exception ex)
            {
                return "";
            }
        }

        private string FirstUpper(string str)
        {
            if (str != null)
            {
                return str.Substring(0, 1).ToUpper() + str.Substring(1);
            }
            return "";
        }

        private bool IsKey(string col, DataTable info)
        {
            DataRow[] rows = info.Select("COLUMN_NAME = '" + col + "'");
            if (rows.Length != 0)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
    }
}
